#include "stdafx.h"

#include "hwinapplication.h"

namespace harlinn
{
    namespace windows
    {
        HWIN_EXPORT MessageLoop::MessageLoop()
        {
        }

        HWIN_EXPORT MessageLoop::~MessageLoop()
        {
        }

        HWIN_EXPORT int MessageLoop::Run()
        {
            Message message;
            while ( GetMessage(message) )
            {
                TranslateMessage(message);
                DispatchMessage(message);
            }
            return (int)message.wParam;
        }
        
        HWIN_EXPORT int MessageLoop::GetMessage(Message& message)
        {
            int result = ::GetMessage(&message,0,0,0);
            return result;
        }
        HWIN_EXPORT int MessageLoop::TranslateMessage(Message& message)
        {
            int result = ::TranslateMessage(&message);
            return result;
        }
        HWIN_EXPORT Message::Result MessageLoop::DispatchMessage(const Message& message)
        {
            Message::Result result = static_cast<Message::Result>( ::DispatchMessage(&message) );
            return result;
        }


        Application* Application::currentApplication = nullptr;


        HWIN_EXPORT Application::Application( )
            : Base( )
        {
            HRESULT hr = CoInitialize(0);
            CheckHRESULT(hr);

            currentApplication = this;
            INITCOMMONCONTROLSEX icex = {0,};
            icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
            icex.dwICC = 0x0000FFFF;

            InitCommonControlsEx(&icex);
            
            windowClasses = std::make_shared<WindowClasses>();

        }

        HWIN_EXPORT Application::~Application()
        {
            currentApplication = nullptr;
            CoUninitialize();
        }

        HWIN_EXPORT void Application::AddControl(HWND hWnd, Control* control)
        {
            auto it = controls.find(hWnd);
            if(it ==  controls.end())
            {
                controls.insert( std::map<HWND, Control*>::value_type(hWnd,control));
            }
        }

        HWIN_EXPORT void Application::RemoveControl(HWND hWnd)
        {
            controls.erase(hWnd);
        }

        HWIN_EXPORT Control* Application::GetControl(HWND hWnd)
        {
            auto it = controls.find(hWnd);
            if(it ==  controls.end())
            {
                auto result = (*it).second;
                return result;
            }
            return nullptr;
        }


        HWIN_EXPORT std::shared_ptr<Application> Application::Current()
        {
            if(currentApplication)
            {
                return currentApplication->As<Application>();
            }

            return std::shared_ptr<Application>();
        }



        HWIN_EXPORT int Application::Run(std::shared_ptr<Form> mainform)
        {
            
            auto messageLoop = std::make_shared<MessageLoop>();
            int result = Run(mainform,messageLoop);
            return result;
        }


        HWIN_EXPORT int Application::Run(std::shared_ptr<Form> mainform, std::shared_ptr<MessageLoop> messageLoop)
        {
            if(mainform)
            {
                
                mainform->OnDestroy.connect( [](Control*theControl, Message& message)
                    {
                        ::PostQuitMessage(-1);
                    });
                

                mainform->Show();

                int result = messageLoop->Run();
                return result;
            }
            return 0;
        }


        HWIN_EXPORT std::shared_ptr<const WindowClasses> Application::GetWindowClasses() const
        {
            return windowClasses;
        }

        HWIN_EXPORT std::shared_ptr<WindowClasses> Application::GetWindowClasses()
        {
            return windowClasses;
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> Application::GetWindowClass(const String& theClassName )
        {
            auto application = Application::Current();
            if(application)
            {
                auto windowClasses = application->GetWindowClasses();
                if(windowClasses)
                {
                    auto result = windowClasses->GetWindowClass(theClassName);
                    return result;
                }
            }
            return nullptr;
        }
        HWIN_EXPORT std::shared_ptr<WindowClass> Application::GetWindowClass(const wchar_t* theClassName )
        {
            if(theClassName && theClassName[0])
            {
                String className(theClassName);
                return GetWindowClass(theClassName);
            }
            return nullptr;
        }



    };
};
